<?php
namespace service;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use think\facade\Log;

/**
 * 微信服务
 * Class WechatService
 * @package service
 */
class WechatService {

    // 链接前缀
    private static $baseUrl = 'https://api.weixin.qq.com/sns';

    /**
     * 获取令牌
     * @param string $code
     * @return array
     */
    public static function getToken($code = '')
    {
        if (empty($code)) {
            return ['status' => false, 'msg' => '授权码不能为空'];
        }
        $wechatConfig = sysConfig('wechat_open');
        if (empty($wechatConfig['app_id']) || empty($wechatConfig['app_secret'])) {
            return ['status' => false, 'msg' => '平台参数尚未配置'];
        }
        $params = [
            'timeout' => 15,
            'connect_timeout' => 15,
            'query' => [
                'appid' => $wechatConfig['app_id'],
                'secret' => $wechatConfig['app_secret'],
                'code' => $code,
                'grant_type' => 'authorization_code'
            ]
        ];
        // 获取access_token
        try {
            $client = new Client();
            $response = $client->request('GET', self::$baseUrl.'/oauth2/access_token', $params);
            $res = $response->getBody()->getContents();
            // 记录日志方便查错
            Log::info('{date} - 获取令牌 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            $res = json_decode($res, true);
            if (!isset($res['access_token'])) {
                $msg = '';
                if (! empty($res['errcode'])) $msg .= '错误码：'. $res['errcode'];
                if (! empty($res['errmsg'])) $msg .= '错误信息：'. $res['errmsg'];
                return ['status' => false, 'msg' => '获取令牌失败，' . $msg];
            }
            return ['status' => true, 'data' => $res];
        } catch (ServerException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 获取令牌1 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '获取令牌失败1：'.  $res];
        } catch (ClientException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 获取令牌2 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '获取令牌失败2：'.  $res];
        }
    }

    /**
     * 刷新令牌
     * @param string $token
     * @return array
     */
    public static function refreshToken($token = '')
    {
        if (empty($token)) {
            return ['status' => false, 'msg' => '刷新令牌不能为空'];
        }
        $wechatConfig = sysConfig('wechat_open');
        if (empty($wechatConfig['app_id']) || empty($wechatConfig['app_secret'])) {
            return ['status' => false, 'msg' => '平台参数尚未配置'];
        }
        $params = [
            'timeout' => 15,
            'connect_timeout' => 15,
            'query' => [
                'appid' => $wechatConfig['app_id'],
                'refresh_token' => $token,
                'grant_type' => 'refresh_token'
            ]
        ];
        // 刷新令牌
        try {
            $client = new Client();
            $response = $client->request('GET', self::$baseUrl . '/oauth2/refresh_token', $params);
            $res = $response->getBody()->getContents();
            // 记录日志方便查错
            Log::info('{date} - 刷新令牌 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            $res = json_decode($res, true);
            if (! isset($res['access_token'])) {
                $msg = '';
                if (! empty($res['errcode'])) $msg .= '错误码：'. $res['errcode'];
                if (! empty($res['errmsg'])) $msg .= '错误信息：'. $res['errmsg'];
                return ['status' => false, 'msg' => '刷新令牌失败，' . $msg];
            }
            return ['status' => true, 'data' => $res];
        } catch (ServerException $e){
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 刷新令牌1 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '刷新令牌失败1：'.  $res];
        }  catch (ClientException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 刷新令牌2 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '刷新令牌失败2：'.  $res];
        }
    }

    /**
     * 检验授权凭证
     * @param array $data
     * @return array
     */
    public static function checkToken($data = [])
    {
        foreach ($data as $key => $item) {
            if (! in_array($key, ['access_token', 'openid'])) {
                unset($data[$key]);
            }
        }
        if (count($data) != 2) {
            return ['status' => false, 'msg' => '缺少必要参数'];
        }
        $params = [
            'timeout' => 15,
            'connect_timeout' => 15,
            'query' => $data
        ];
        // 检验授权凭证
        try {
            $client = new Client();
            $response = $client->request('GET', self::$baseUrl.'/auth', $params);
            $res = $response->getBody()->getContents();
            // 记录日志方便查错
            Log::info('{date} - 检验授权 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            $res = json_decode($res, true);
            $msg = '';
            if (! isset($res['errcode']) || $res['errcode'] > 0) {
                if (! empty($res['errcode'])) $msg .= '错误码：'. $res['errcode'];
                if (! empty($res['errmsg'])) $msg .= '错误信息：'. $res['errmsg'];
                $msg = '无效授权，'. $msg;
            }
            return ['status' => true, 'msg' => $msg];
        } catch (ServerException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 检验授权1 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '无效授权1：'.  $res];
        } catch (ClientException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 检验授权2 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '无效授权2：'.  $res];
        }
    }

    /**
     * 获取用户信息
     * @param array $data
     * @return array
     */
    public static function getUserInfo($data = [])
    {
        // 检测令牌
        $res = self::checkToken($data);
        if (! $res['status']) {
            return $res;
        }
        // 令牌无效
        if ($res['msg']) {
            if (empty($data['refresh_token'])) {
                return ['status' => false, 'msg' => '令牌无效'];
            }
            $res = self::refreshToken($data['refresh_token']);
            if (! $res['status']) {
                return $res;
            }
            $data = $res['data'];
        }
        $params = [
            'timeout' => 15,
            'connect_timeout' => 15,
            'query' => [
                'access_token' => $data['access_token'],
                'openid' => $data['openid'],
                'lang' => 'zh_CN'
            ]
        ];
        // 获取用户信息
        try {
            $client = new Client();
            $response = $client->request('GET', self::$baseUrl.'/userinfo', $params);
            $res = $response->getBody()->getContents();
            // 记录日志方便查错
            Log::info('{date} - 获取用户信息 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            $res = json_decode($res, true);
            if (isset($res['errcode']) || isset($res['errmsg'])) {
                $msg = '';
                if (! empty($res['errcode'])) $msg .= '错误码：'. $res['errcode'];
                if (! empty($res['errmsg'])) $msg .= '错误信息：'. $res['errmsg'];
                return ['status' => false, 'msg' => '获取失败，'. $msg];
            }
            return ['status' => true, 'data' => array_merge($res, ['access_token' => $data['access_token'], 'refresh_token' => $data['refresh_token']])];
        } catch (ServerException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 获取用户信息1 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '获取用户信息1：'.  $res];
        } catch (ClientException $e) {
            $res = $e->getMessage();
            // 记录日志方便查错
            Log::info('{date} - 获取用户信息2 - 返回内容：{res}', ['date' => date('Y-m-d H:i:s'), 'res' => $res]);
            return ['status' => false, 'msg' => '获取用户信息2：'.  $res];
        }
    }
}
